
--真正处理的情形应该与玩家操作隔离开，在麻将中有的操作不一定会执行

local card = require "card"
local player = class("player")
local inspect = require "inspect"
local skynet = require "skynet"

function table_copy_table(ori_tab)
	if (type(ori_tab) ~= "table") then
		return nil
	end
	local new_tab = {}
	for i,v in pairs(ori_tab) do
		local vtyp = type(v)
		if (vtyp == "table") then
			new_tab[i] = table_copy_table(v)
		elseif (vtyp == "thread") then
			new_tab[i] = v
		elseif (vtyp == "userdata") then
			new_tab[i] = v
		else
			new_tab[i] = v
		end
	end
	return new_tab
end

function player:init()
	self.set = {}			--玩家手牌
	self.chi_set = {}		--已经吃的牌
	self.peng_set = {}		--已经碰的牌
	self.gang_set = {}		--已经杠的牌
	self.black_gang_set = {}--暗杠的牌
	self.flower = {}		--花牌
	self.collect_reward = {}--花牌的收集奖励
	self.recent_play = nil

	self.score = 0
	self.action_can_do = {}	--玩家可以进行的动作：吃碰杠胡
	self.ting = false
	self.play_front = {}

	self.chi_user = {}		--吃的牌的用户信息
	self.peng_user = {}		--碰的牌的用户信息
	self.gang_user = {}		--杠的牌的用户信息
	self.chi_peng_gang_num = {}

	self.continue = true --出现承包,true为坚持,false为放弃
	self.tth_chi = false
end

function player:ctor(game)
	self.game = game
end

function player:get_peng_data()
	local ret = {}
	for k,v in pairs(self.peng_user) do
		if v ~= 0 then
			table.insert(ret,{card = k , playerid = v})
		end
	end
	return ret
end


function player:get_gang_data()
	local ret = {}
	for k,v in pairs(self.gang_user) do
		if v ~= 0 then
			table.insert(ret,{card = k , playerid = v})
		end
	end
	return ret
end

function player:add_score(n)
	self.score = self.score  + n
end

function player:set_chi_user(turn,card)
	self.chi_user[card] = {}
	table.insert(self.chi_user[card],turn)
	self:set_chi_peng_gang_num(turn)
	self.tth_chi = true
end

function player:is_chi()
	--if #self.chi_user > 0 then
		--return true
	--end
	return self.tth_chi
end

function player:set_peng_user(turn,card)
	self.peng_user[card] = turn
	self:set_chi_peng_gang_num(turn)
end

function player:set_gang_user(turn,card,target,opt)
	self.gang_user[card] = turn
	if self.peng_user[card] then
		self.gang_user[card] = self.peng_user[card]
		self.peng_user[card] = 0
	end
	if not opt then
		self:set_chi_peng_gang_num(turn)
	end
end

function player:set_chi_peng_gang_num(turn)
	if not self.chi_peng_gang_num[turn] then
		self.chi_peng_gang_num[turn] = 1
	else
		self.chi_peng_gang_num[turn] = self.chi_peng_gang_num[turn] + 1
	end
end

function player:get_san_tan(turn)
	local peng_gang = {}
	for k,v in pairs(self.chi_peng_gang_num) do
		if k == turn then
			if v >= 3 then
				return k
			end
		end
	end
end

function player:get_close_hu()
	for k,v in pairs(self.chi_peng_gang_num) do
		if v == 4 then
			return k
		end
	end
end

function player:get_chi_user()
	return self.chi_user
end

function player:get_peng_user()
	return self.peng_user
end

function player:get_gang_user()
	return self.gang_user
end

function player:get_score()
	return self.score
end

function player:get_set()
	return self.set
end

function player:get_chi_set()
	return self.chi_set
end

function player:get_peng_set()
	return self.peng_set
end

function player:get_gang_set()
	return self.gang_set
end

function player:get_black_gang_set()
	return self.black_gang_set
end

function player:get_flower()
	return self.flower
end

function player:get_collect_reward()
	return self.collect_reward
end

function player:get_flower_score()
	local score = 0
	for i,v in ipairs(self.collect_reward) do
		if v then
			score = score + 2
		end
	end
	score = score + #self.flower + #self.gang_set + #self.black_gang_set * 2
	return score
end

function player:take_card_start(t)
	self.set = t
end


function player:take_card(c)
	--self.recent_take = c
	card:add(self.set,c)
	card:sort_card(self.set)
end
--刚刚摸到的牌
function player:set_this_turn_get(c)
	self.this_turn_get = c
end

function player:get_this_turn_get()
	return self.this_turn_get
end
--整理手牌
function player:arrange_set()	
	card:sort_card(self.set)
end


function player:fill_flower_start()
	card:sort_card(self.set)
	local num = 0
	local t = {}
	for i=#self.set,1,-1 do
		if card:get_type(self.set[i]) == FLOWER then
			card:add(t,self.set[i])
			self:add_flower_score(self.set[i])
			card:drop(self.set,self.set[i])
			num = num + 1 
		end
	end
	return t
end

function player:fill_flower(c)
	self:add_flower_score(c)
end

function player:add_flower_score(c)
	function get_direct_num(set,value)
		local num = 0
		for i,v in ipairs(set) do
			if card:get_value(v) == value then
				num = num +1
			end
		end
		return num
	end

	function get_season_num(set)
		local num = 0
		for i,v in ipairs(set) do
			if card:get_value(v) >= 8 and card:get_value(v) <= 11 then
				num = num + 1
			end 
		end
		return num
	end

	function get_flower_num(set)
		local num = 0
		for i,v in ipairs(set) do
			if card:get_value(v) >= 12 then
				num = num + 1
			end 
		end
		return num
	end

	card:sort_card(self.flower)
	card:add(self.flower,c)
	local val = card:get_value(c)
	if val  <= 7 then
		if get_direct_num(self.flower,val) == 4  then
			self.collect_reward[val] = true
		end
	elseif  val >= 8 and val <= 11 then
		if get_season_num(self.flower,val) == 4  then
			self.collect_reward[8] = true
		end
	elseif val >= 12 then
		if get_flower_num(self.flower,val) == 4  then
			self.collect_reward[9] = true
		end
	end
end

function player:play_card(c)
	self.recent_play = c
	if self.this_turn_get ~= c then
		card:drop(self.set,c)
		card:add(self.set,self.this_turn_get)
	end
	self.this_turn_get = nil
	table.insert(self.play_front,c)
	self.action_can_do = {}
end

function player:gang_yao_play(c)
	self.recent_play = c
	table.insert(self.play_front,c)
	self.action_can_do = {}
end

function player:get_play_front()
	return self.play_front
end
--删牌有问题 杠摇
function player:remove_front()
	table.remove(self.play_front)
end

function player:is_valid_play(c)
	if 	self.this_turn_get == c or card:has(self.set,c) then
		return true
	end
	return false
end

function player:auto_play()
	if self.this_turn_get then
		local c = self.this_turn_get
		self.this_turn_get = nil
		self.recent_play = c
		table.insert(self.play_front,c)
		return c
	else
		card:sort_card(self.set)
		self.recent_play = table.remove(self.set)
		if self.recent_play == card then
			self.recent_play = table.remove(self.set,1)
		end
		table.insert(self.play_front,c)
		return self.recent_play
	end
end


function player:get_recent_play()
	return self.recent_play
end
function player:set_action_can_do(t)
	self.action_can_do = t
end

function player:get_action_can_do()
	return self.action_can_do
end

function player:chi(c,t)
	print(card:get_card_string(t))
	local a = t[1]
	local b = t[2]
	card:add(t,c)
	card:sort_card(t)
	if t[1] + 1~= t[2] or t[2] + 1 ~= t[3] then
		skynet.error("chi is invalid",inspect(t),t[1] + 1~= t[2] , t[2] + 1 ~= t[3])
		error("chi is invalid","c",inspect(c),"t",inspect(t))
		return
	end

	card:drop(self.set,a)
	card:drop(self.set,b)
	card:sort_card(self.set)
	local single = table.remove(self.set)
	self:set_this_turn_get(single)			--set the last as this turn get
	if card:has(t,c) then
		card:drop(t,c)
		table.insert(t,1,c)
	end
	local tb = {}
	table.insert(tb,c)
	table.insert(tb,a)
	table.insert(tb,b)
	table.insert(self.chi_set,tb)
	return tb
end

function player:peng(c)
	local nums = card:get_specify_nums(self.set,c)
	if nums < 2 then
		skynet.error("peng is invalid","c",inspect(c),"nums",nums,inspect(self.set))
		error("peng is invalid")
		return
	end 
	card:drop(self.set,c)
	card:drop(self.set,c)
	
	card:sort_card(self.set)
	local single = table.remove(self.set)
	self:set_this_turn_get(single)			--set the last as this turn get
	local t = {}
	for i=1,3 do
		card:add(t,c)
	end
	table.insert(self.peng_set,t)
	return t
end

function player:gang(c)
	local nums = card:get_specify_nums(self.set,c)
	if nums < 3 then
		skynet.error("gang is invalid",inspect(self.set),"c",inspect(c),"nums",nums)
		error("gang is invalid","c",inspect(c),"nums",nums)
		return
	end 
	card:drop(self.set,c)
	card:drop(self.set,c)
	card:drop(self.set,c)
	local t = {}
	for i=1,4 do
		card:add(t,c)
	end
	table.insert(self.gang_set,t)
	return t
end

function player:white_gang(c)
	for i=1,#self.peng_set do
		if self.peng_set[i][1] == c then
			local t = table.remove(self.peng_set,i)
			card:add(t,c)
			table.insert(self.gang_set,t)
			if card:has(self.set,c) then
				card:drop(self.set,c)
				card:add(self.set,self.this_turn_get)
				self.this_turn_get = nil
			elseif self.this_turn_get == c then
				self.this_turn_get = nil
			end
			self:set_gang_user(self.peng_user[c],c,nil,true)
			skynet.error("self.gang_user",string.format("%s %s \x1b[0m", "\x1b[32m",inspect(self.gang_user)))
			skynet.error("self.peng_user",string.format("%s %s \x1b[0m", "\x1b[32m",inspect(self.peng_user)))
			return t,self.gang_user[c]
		end
	end
end

function player:black_gang(c)
	-- local nums = card:get_specify_nums(self.set,c)
	-- if nums < 3 then
	-- 	error("black gang is invalid")
	-- 	return
	-- end 
	if self.this_turn_get ==  c then
		self.this_turn_get = nil
	else
		card:add(self.set,self.this_turn_get)
		card:drop(self.set,c)
		self.this_turn_get = nil
	end
	
	card:drop(self.set,c)
	card:drop(self.set,c)
	card:drop(self.set,c)
	local t = {}
	for i=1,4 do
		card:add(t,c)
	end
	table.insert(self.black_gang_set,t)
	return t
end

--杠自己
function player:check_gang_self()

	for i,v in ipairs(self.peng_set) do
		print(i,card:get_card_string(v))
	end
	for i,v in ipairs(self.peng_set) do
		if card:has(self.set,v[1]) or self.this_turn_get == v[1] then
			return true
		end
	end

	local nums = 1
	local set_t = table_copy_table(self.set)
	card:add(set_t,self.this_turn_get)
	card:sort_card(set_t)
	for i=2,#set_t do
		if set_t[i - 1] == set_t[i] then
			nums = nums + 1
		else
			nums = 1
		end
		
		if nums == 4 then
			return true
		end 
	end
end

function player:set_continue(val)
	self.continue = val
end

function player:is_continue()
	return self.continue
end

function player:is_valid_chi(c,t1)
	local t = table_copy_table(t1)
	--print(card:get_card_string(t))
	--print("is_valid_chi!!!",c)
	card:add(t,c)
	card:sort_card(t)
	--print(card:get_card_string(t))
	if t[1] + 1~= t[2] or t[2] + 1 ~= t[3] then
		skynet.error("chi is invalid",inspect(t),t[1] + 1~= t[2] , t[2] + 1 ~= t[3])
		error("chi is invalid")
		return false
	else
		return true
	end
end

function player:is_valid_peng(c)
	local nums = card:get_specify_nums(self.set,c)
	if nums < 2 then
		skynet.error("peng is invalid","c",inspect(c),"nums",nums,inspect(self.set))
		error("peng is invalid")
		return false
	else
		return true
	end
end

function player:is_valid_gang(c)
	local nums = card:get_specify_nums(self.set,c)
	if nums < 3 then
		skynet.error("gang is invalid",inspect(self.set),"c",inspect(c),"nums",nums)
		error("gang is invalid")
		return false
	else
		return true
	end
end


function player:is_valid_black_gang(c)
	local nums = card:get_specify_nums(self.set,c)
	if self.this_turn_get == c then
		nums = nums + 1
	end
	if nums < 3 then
		skynet.error("gang is invalid",inspect(self.set),"c",inspect(c),"nums",nums)
		print("black gang is invalid")
		return false
	else
		return true
	end
end

function player:is_valid_white_gang(c)
	print("is_valid_white_gang",card:get_c(c))
	if card:has(self.set,c) or self.this_turn_get == c then
		for i,v in ipairs(self.peng_set) do
			if v[1] == c then
				return true
			end
		end
	end
	return false
end

function player:ting_pai()
	self.ting = true
end

function player:is_ting()
	return self.ting
end

function player:set_host(yes)
	if yes then
		self.host = true	
	end
end

function player:is_host()
	return self.host
end
--true 表示不需要
function player:need_258()
	if  #self:get_set() <= 2 then
		return true
	end
	if card:qing_yi_se(self:get_all_card()) then
		return true
	end
end

function player:get_chi_ting()
	local t = {}
	for i,v1 in ipairs(self.chi_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	return t
end

function player:get_peng_ting()
	local t = {}
	for i,v1 in ipairs(self.peng_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	return t
end

function player:get_gang_ting()
	local t = {}
	for i,v1 in ipairs(self.gang_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	for i,v1 in ipairs(self.black_gang_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	return t
end

function player:get_all_card()
	local t = {}
	
	for i,v in ipairs(self.set) do
		table.insert(t,v)
	end
	for i,v1 in ipairs(self.chi_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	
	for i,v1 in ipairs(self.peng_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	
	for i,v1 in ipairs(self.gang_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	
	for i,v1 in ipairs(self.black_gang_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	
	if self.this_turn_get then
		table.insert(t,self.this_turn_get)
	end
	return t
end

function player:get_set_ex(c)
	local set = table_copy_table(self:get_set())
	local nums = card:get_specify_nums(set,c)
	if nums == 3 then
		for i=1,nums do
			card:drop(set,c)
		end
	end
	return set
end

function player:get_all_card_and_play_front()
	local t = self:get_all_card()

	for k,v in pairs(self.play_front) do
		table.insert(t,v)
	end
	return t
end

function player:get_visible_cards()
	local t = {}
	for i,v1 in ipairs(self.chi_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	
	for i,v1 in ipairs(self.peng_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	
	for i,v1 in ipairs(self.gang_set) do
		for k,v2 in ipairs(v1) do
			table.insert(t,v2)
		end
	end
	for k,v in pairs(self.play_front) do
		table.insert(t,v)
	end
	return t
end

function player:get_result_set()
	local card_info = {}
	card_info.recent_play = self.recent_play
	card_info.set = {}
	card_info.chi = {}
	for k,v in pairs(self.chi_set) do
		local temp = {}
		temp.cards = v
	 	table.insert(card_info.chi,temp)
	end
	card_info.peng = {}
	for k,v in pairs(self.peng_set) do
		local temp = {}
		temp.cards = v
	 	table.insert(card_info.peng,temp)
	end
	card_info.gang = {}
	for k,v in pairs( self.gang_set) do
		local temp = {}
		temp.cards = v
	 	table.insert(card_info.gang,temp)
	end
	card_info.black_gang = {}
	for k,v in pairs( self.black_gang_set) do
		local temp = {}
		temp.cards = v
	 	table.insert(card_info.black_gang,temp)
	end
	card_info.set.cards = table_copy_table(self:get_set())
	--card_info.get_this_turn = self:get_this_turn_get()
	table.insert(card_info.set.cards,player:get_this_turn_get())
	return card_info
end

return player
-- local M = {}
-- function M.new(game)
-- 	return setmetatable({
-- 		game = game
-- 	}, {__index = player})
-- end
-- return M
